package com.szwistar.common.datastruct;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.j256.ormlite.field.DataPersisterManager;
import com.j256.ormlite.field.FieldType;
import com.j256.ormlite.field.SqlType;
import com.j256.ormlite.field.types.StringType;

class XxxSerializer extends JsonSerializer<JsonableType> {
	static final Logger LOG = LoggerFactory.getLogger(XxxSerializer.class);

	@Override
	public void serialize(JsonableType value, JsonGenerator jgen, SerializerProvider provider) {
		try {
			jgen.writeString(value.toJson());
		} catch (Exception e) {
			LOG.error("序列化失败！", e);
		}
	}
}

class XxxDeserializer extends JsonDeserializer<JsonableType> {
	static final Logger LOG = LoggerFactory.getLogger(XxxDeserializer.class);

	// 派生实现类
	Class<? extends JsonableType> implClazz;

	public XxxDeserializer(Class<? extends JsonableType> implClazz) {
		super();
		this.implClazz = implClazz;
	}

	@Override
	public JsonableType deserialize(JsonParser jp, DeserializationContext ctxt) throws JsonProcessingException {
		try {
			return JsonlizedOrmTypeHelper.parseJson(implClazz, jp.getValueAsString());
		} catch(Exception e) {
			LOG.error("ORM 适配器 {} 解析数据失败！", implClazz.toString(), e);
			return null;
		}
	}
}

class OrmableType extends StringType {
	static final Logger LOG = LoggerFactory.getLogger(OrmableType.class);

	// 派生实现类
	Class<?> implClazz;
	// 对应数据库字段默认宽度
	int defaultWidth = 0;

	OrmableType(Class<?> clazz, int defaultWidth) {
		// 在 数据库字符串型字段 <-> OrmableType类型 之间转换
		// !!! 注意：如果字段大于 10K，则要使用 LONG_STRING，以防存储不下！
		super(((defaultWidth < 10*1024) ? SqlType.STRING : SqlType.LONG_STRING), new Class<?>[]{ clazz });
		this.implClazz = clazz;
		this.defaultWidth = defaultWidth;
	}

	// 修改默认的数据库字段宽度
	@Override
	public int getDefaultWidth() {
		return defaultWidth;
	}

	// Java 对象 转换为 数据库字段
	@Override
	public Object javaToSqlArg(FieldType fieldType, Object obj) {
		try {
			if(obj instanceof JsonableType) {
				return ((JsonableType) obj).toJson();
			} else {
				return JsonMapper.toJson(obj);
			}
		} catch (Exception e) {
			LOG.error("{} 的字段 {} 序列化失败！", obj, fieldType, e);
			return null;
		}
	}

	// 数据库字段 转换为 Java 对象
	@Override
	public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) {
		try {
			return JsonlizedOrmTypeHelper.parseJson(implClazz, (String)sqlArg);
		} catch(Exception e) {
			LOG.error("ORM 适配器 {} 解析 '{}' 字段数据 '{}' 失败！", implClazz.toString(), fieldType.getFieldName(), sqlArg, e);
			return null;
		}
	}
}

public class JsonlizedOrmTypeHelper {
	/**
	 * 类型注册
	 * @param clazz 实际的 JsonlizedOrmType 派生实现类
	 * @param defaultWidth 默认的数据库字段宽度
	 */
	public static void register(Class<? extends JsonableType> typeClazz, int defaultWidth) {
		// 注册自定义数据类型“JSON 序列化/反序列化”支持包
		SimpleModule module = new SimpleModule();
		module.addSerializer(typeClazz, new XxxSerializer());
		module.addDeserializer(JsonableType.class, new XxxDeserializer(typeClazz));
		JsonMapper.getMapper().registerModule(module);

		// 注册自定义数据类型“数据库持久化”支持包
		DataPersisterManager.registerDataPersisters(new OrmableType(typeClazz, defaultWidth));
	}

	public static void register(Class<? extends JsonableType> typeClazz) {
		register(typeClazz, 255);
	}

	/**
	 * 类型注册
	 * @param clazz 实际的 JsonlizedOrmType 派生实现类
	 * @param defaultWidth 默认的数据库字段宽度
	 */
	public static void registerOrmTypeOnly(Class<?> typeClazz, int defaultWidth) {
		// 注册自定义数据类型“数据库持久化”支持包
		DataPersisterManager.registerDataPersisters(new OrmableType(typeClazz, defaultWidth));
	}

	/**
	 * 解析 JSON
	 * @param clazz 类型
	 * @param json JSON 字符串
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	protected static <T> T parseJson(Class<T> clazz, String json) throws Exception {
		Method methodParseJson = null;
		Constructor<T> jsonConstructor = null;
		Method methodfromJson = null;

		// 1.尝试调用实现类的静态方法:
		// public static Xxx parseJson(String json)
		try { methodParseJson = clazz.getMethod("parseJson", String.class); } catch(Exception e) {}
		if(methodParseJson != null) {
			return (T) methodParseJson.invoke(null, json);
		}

		// 2.尝试调用 Json 构造方法:
		// public Xxx(String json)
		try { jsonConstructor = clazz.getConstructor(String.class); } catch(Exception e) {}
		if(jsonConstructor != null) {
			return jsonConstructor.newInstance(json);
		}

		// 3.调用默认构造函数创建对象，并调用 fromJson() 方法:
		// public void fromJson(String json)
		try { methodfromJson = clazz.getMethod("fromJson", String.class); } catch(Exception e) {}
		if(methodfromJson != null) {
			Object obj = clazz.newInstance();
			methodfromJson.invoke(obj, json);
			return (T)obj;
		}

		throw Utils.newException("无法解析 JSON 为 %s 对象！\n%s", clazz.getSimpleName(), json);
	}
}
